from __future__ import division

from core import *

from .culture import Culturable
from .goods import Consumable


class HomeSupplier(Ability):
    home_supply =_ (None)


class Civilian(Walker):
    color    =_ (White + Black)
    speed    =_ (5)
    distance =_ (50)
    
    def day(self, day, month, year):
        for market in self.tile.nearby(HomeSupplier, radius = 5):
            for type in market.home_supply:
                for subtype in type.all_concrete_subtypes:
                    free  = self.home.storage.free_storage_for(subtype)
                    goods = subtype(int(10 * market.efficiency)).max(free)
                    
                    if goods.quantity == 0:
                        continue
                    
                    self.home.transfer_from(market.storage, goods)


class House(StaffedBuilding, Culturable):
    name         =_ ('House')
    size         =_ (2)
    cost         =_ (25)
    color        =_ (Red)
    worker_ratio =_ (0.5)
    profession   =_ (Civilian)
    
    level    = Attribute(initial = 0, writable = True)
    people   = Attribute(initial = 0, writable = True)
    is_full  = Attribute(initial = False, writable = True)
    earnings = Attribute(initial = 0, writable = True)
    
    @property
    def categories(self):
        return Consumable.subtypes
    
    @property
    def stores(self):
        return (good(100) for category in self.categories for good in category.all_concrete_subtypes)
    
    @property
    def capacity(self):
        return 20 + self.level * 4
    
    @property
    def staffing_level(self):
        return self.people / self.capacity
    
    @property
    def space_left(self):
        return max(self.capacity - self.people, 0)
    
    def add_people(self, n):
        self.change_people(max(min(self.capacity - self.people, n), 0))
    
    def remove_people(self, n):
        self.change_people(-max(min(self.people, n), 0))
    
    def change_people(self, n):
        self.people          += n
        self.city.population += n
        self.city.workers    += n * self.worker_ratio
        self.check_full()
    
    def check_full(self):
        self.is_full = (self.people >= self.capacity)
    
    def payday(self):
        self.earnings /= 2
        self.earnings += self.people * self.city.wage * self.city.tax * (1 - self.city.unemployment) * self.level
    
    def day(self, day, month, year):
        super(House, self).day(day, month, year)
        
        self.consume_goods()
    
    @property
    def happiness_name(self):
        return ('Angry', 'Unhappy', 'Content', 'Happy', 'Ecstatic')[self.happiness + 2]
    
    @property
    def happiness(self):
        happiness = [self.relative_happiness_in(category) for category in self.categories]
        excellent = len([happy for happy in happiness if happy >=  2])
        good      = len([happy for happy in happiness if happy ==  1])
        bad       = len([happy for happy in happiness if happy == -1])
        horrible  = len([happy for happy in happiness if happy <= -2])        
        points    = -4 * horrible + -2 * bad + good + 2 * excellent
        
        if points < -2:
            return -2
        elif points == -1:
            return -1
        elif points == 0:
            return 0
        elif points < len(self.categories):
            return 1
        else:
            return 2
    
    def relative_happiness_in(self, category):
        return int(self.happiness_in(category) - self.level)
    
    def happiness_in(self, category):
        return sum(type.happiness for type in self.stored_types_in(category))
    
    def stored_types_in(self, category):
        return set(type for type in category.all_concrete_subtypes if self.number_left_of(type) > 0)
    
    def consume_goods(self):
        for category in self.categories:
            types = self.stored_types_in(category)
            
            if not types:
                continue
            
            type = random.choice(list(types))
            
            if self.chance(type.consumed * self.people / 100):
                self.consume(type(1))
    
    def construction(self):
        self.city.housing += self.capacity
    
    def destruction(self):
        self.city.housing -= self.capacity
        
        self.remove_people(self.people)
    
    @property
    def state(self):
        return {'Level'    : lambda: self.level,
                'Happiness': lambda: '%s (%s)' % (self.happiness_name,
                                                  '; '.join('%s: %.1f' % (category.plural[0],
                                                                          self.happiness_in(category))
                                                            for category in self.categories)),
                'Earnings' : lambda: self.earnings,
                'People'   : lambda: '%d/%d' % (self.people, self.capacity)}
